home *** CD-ROM | disk | FTP | other *** search
- /***********************************************************
- File: ATMDLPI.c
-
- Contains: ATM Open Transport Streams PCI DLPI driver
-
- Written by:
-
- Copyright: © 1994 by Apple Computer, Inc., all rights reserved.
-
- Change History (most recent first):
-
- To Do:
- ***********************************************************/
-
- /***********************************************************
- INCLUDES
- ***********************************************************/
-
- #include "ATMDLPI.h"
- #include "PCIRoutines.h"
- #include "HWSpecific.h"
- #include "ATMDebug.h"
-
- /***********************************************************
- EXTERNS
- ***********************************************************/
-
- /***********************************************************
- FUNCTION PROTOTYPES
- ***********************************************************/
-
- OSErr InitCFMRoutine(CFragInitBlock *theInitBlock);
- void TerminateCFMRoutine(void);
-
- OSStatus ValidateHardware(RegEntryID *theID);
- install_info* GetOTInstallInfo();
- Boolean InitStreamModule(RegEntryID *theID);
- void TerminateStreamModule(void);
-
- static int atm_open(queue_t* rdq, dev_t* dev, int flag, int sflag, cred_t* creds);
- static int atm_close(queue_t* rdq, int flag, cred_t* creds);
- static int atm_rput(queue_t* q, mblk_t* mp);
- static int atm_rsrv(queue_t* q);
- static int atm_wput(queue_t* q, mblk_t* mp);
- static int atm_wsrv(queue_t* q);
-
- static void atm_ioctl(queue_t* q, mblk_t* mp);
- static void atm_flush(queue_t* q, mblk_t* mp);
-
- static int ATMDLPI_info_req(MinorDeviceTableEntry* minorDev, mblk_t* mp);
-
- static int ATMDLPI_phy_addr_req(MinorDeviceTableEntry* minorDev, mblk_t* mp);
- static int all_minors_unbound();
- static int ATMDLPI_set_phy_addr_req(MinorDeviceTableEntry* minorDev, mblk_t* mp);
-
- static int ATMDLPI_bind_req(MinorDeviceTableEntry* minorDev, mblk_t* mp);
- static int ATMDLPI_unbind_req(MinorDeviceTableEntry* minorDev, mblk_t* mp);
-
- static int validate_pvc(PVCAddress* pvc);
- static int validate_aal(AALType aal);
- static int validate_traffic(TrafficDesc* traffic);
- static int validate_qos(QOSClass qos);
-
- static int ATMDLPI_connect_req(MinorDeviceTableEntry* minorDev, mblk_t* mp);
- static int ATMDLPI_disconnect_req(MinorDeviceTableEntry* minorDev, mblk_t* mp);
-
- static int disconnect_all_pvc(MinorDeviceTableEntry* minorDev);
- static int disconnect_pvc(MinorDeviceTableEntry* minorDev, ConnectTableEntry* conn);
-
- static int ATMDLPI_IOCTL_subs_connect(MinorDeviceTableEntry* minorDev, mblk_t* mp);
- static int ATMDLPI_IOCTL_subs_disconnect(MinorDeviceTableEntry* minorDev, mblk_t* mp);
-
- static int ATMDLPI_udqos_req(MinorDeviceTableEntry* minorDev, mblk_t* mp);
-
- static void ATMDLPI_uderror_ind(MinorDeviceTableEntry* minorDev, UInt8 *dest, UInt32 destlen,
- UInt32 err, UInt32 uerr);
-
- static int ATMDLPI_unitdata_req(MinorDeviceTableEntry* minorDev, mblk_t* mp, UInt8 defaultQFlag);
- void ATMDLPI_unitdata_ind(ConnectTableEntry* conn, UInt16 vpi, UInt16 vci, mblk_t* mp);
-
- static int ATMDLPI_error_ack(MinorDeviceTableEntry* minorDev, mblk_t *ack_mp, UInt32 prim,
- UInt32 err, UInt32 uerr);
- static int ATMDLPI_ok_ack(MinorDeviceTableEntry* minorDev, mblk_t* mp, UInt32 primitive);
-
- static void enable_write_queue(SInt32 p);
- static void schedule_write_queue(MinorDeviceTableEntry* minorDev, SInt32 size);
-
- ConnectTableEntry* find_connection(UInt16 vpi, UInt16 vci, UInt32 flags);
-
- /***********************************************************
- GLOBALS
- ***********************************************************/
-
- PortPrivateData* gPortPrivateData = NULL;
-
- static char tempstr[255];
-
- //-----------------------------------------------------------------------------------------
- // STREAMS Structures
- //-----------------------------------------------------------------------------------------
-
- static struct module_info moduleInformation =
- {
- kATMModuleID, // indicates this dlpi is ethernet
- kModuleDeviceInfoName,
- kMinAAL5PDU, // minimum packet data size
- kMaxAAL5PDU, // maximum packet data size
- kQueueHighMark, // Hi water mark for queue
- kQueueLowMark // Lo water mark for queue
- };
-
-
- static struct qinit readSide =
- {
- atm_rput, /* the read put routine should never be called */
- atm_rsrv, /* Service routine for "incoming" data */
- atm_open, /* Our open routine */
- atm_close, /* Our close routine */
- NULL, /* reserved for future use */
- &moduleInformation,
- NULL /* no module_stat structure */
- };
-
-
- static struct qinit writeSide =
- {
- atm_wput, /* Our write-side "put" routine */
- atm_wsrv, /* service routine on the write_side queue */
- NULL, /* no module open needed for write side */
- NULL, /* no module close needed for write side */
- NULL, /* reserved for future use */
- &moduleInformation,
- NULL /* no module_stat structure */
- };
-
-
- static struct streamtab streamTabInformation =
- {
- &readSide,
- &writeSide,
- NULL, /* lower read/write qinit (multiplexors only) */
- NULL
- };
-
- static struct install_info theInstallInformation =
- {
- &streamTabInformation,
- kOTModIsDriver, // install flags
- SQLVL_MODULE, // Synchronization level
- 0, // Shared writer list buddy
- 0 // Flag - set to 0
- };
-
- //-----------------------------------------------------------------------------------------
- // Description:
- // This data stucture entry point is exported through the cfm mechanism. Information
- // about the hardware that this driver works with is located in this structure.
- //
- //-----------------------------------------------------------------------------------------
-
- DriverDescription TheDriverDescription =
- {
- // Signature Info
- kTheDescriptionSignature, // signature always first
- kInitialDriverDescriptor, // version second
-
- // Type Info
- kPCIDeviceInfoName, // Our name, module info name must match
- 1,0,0,0, // Major, Minor, Stage, Rev
-
- // OS Runtime Info
- kDriverIsUnderExpertControl, // Runtime Options
- "\patm", // should be kATMName (as a pascal string)
- 0,0,0,0,0,0,0,0, // reserve 8 longs
-
- // OS Service Info
- 1, // Number of Service Categories
- kServiceCategoryOpenTransport, // We support the 'otan' category
- OTPCIServiceType(kOTATMDevice,0,0,1),
- 1,0,0,0 // Major, Minor, Stage, Rev
- };
-
-
- /*
- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- + +
- + F U N C T I O N S +
- + +
- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- */
-
- /***********************************************************
- *
- * CODE FRAGMENT MANAGER INITIALIZATION AND TERMINATION
- *
- ************************************************************/
-
- //-----------------------------------------------------------------------------------------
- // Description:
- // This is the cfm initialization routine. It is not required and is almost a
- // duplication of the InitStreamModule() routine.
- //
- // Input:
- // theInitBlock - block containing various cfm information
- //
- // Output:
- // NONE
- //
- //-----------------------------------------------------------------------------------------
- OSErr InitCFMRoutine(CFragInitBlock *theInitBlock)
- {
- return kOTNoError;
- }
-
- //-----------------------------------------------------------------------------------------
- // Description:
- // This is the cfm termination routine. It is not required and is almost a
- // duplication of the TerminateStreamModule() routine.
- //
- // Input:
- // NONE
- //
- // Output:
- // NONE
- //
- //-----------------------------------------------------------------------------------------
- void TerminateCFMRoutine(void)
- {
-
- }
-
- /***********************************************************
- *
- * ATM DRIVER DLPI : INSTALLATION AND INITIALIZATION
- *
- ************************************************************/
-
- //-----------------------------------------------------------------------------------------
- // Description:
- // This routine is used by the driver to validate that our hardware is available.
- // By using the ID we can find out the assigned address of the card.
- // Next we should check if this driver can work with that card. If the driver can
- // use the card then return kOTNoError. If your card can be accessed
- // through either address space it is better to use memory space so you don't
- // have to use the Expansion Manager for every access.
- //
- // Keep in mind that even if the dlpi responds with kOTNoError the user may decide
- // to not use your card...so the card state should be in the same state as when
- // the routine was called. In other words, turn off the card before you leave
- // this routine and also deallocate any memory that you allocating. The dlpi
- // may be unloaded from memory so do not expect to have globals between the
- // the ValidateHardware routine and InitStreamModule.
- //
- // Input:
- // theID - node id of the card in the system registry
- //
- // Output:
- // kOTNoError if the hardware is available
- // kENXIOErr, if could not obtain card base address or driver does not work with card
- //
- //-----------------------------------------------------------------------------------------
- OSStatus ValidateHardware(RegEntryID *theID)
- {
- OSStatus error = kENXIOErr; // default error code
- UInt32 cardAddress, spaceAllocated;
-
- if ( GetPCICardBaseAddress(theID, &cardAddress,
- kPCIConfigBase14Offset, &spaceAllocated) == kOTNoError)
- { // check if our driver works with this card
- if (ABCVendorIsThisOurCard(theID, cardAddress))
- error = kOTNoError;
- }
-
- return error;
- }
-
- //-----------------------------------------------------------------------------------------
- // Description:
- // This routine returns a pointer to the install_info structure. The
- // name of the routine must be "GetOTInstallInfo" because OT loads the
- // the function pointer by name.
- //
- // Input:
- // NONE
- //
- // Output:
- // returns the install_info pointer
- //
- //-----------------------------------------------------------------------------------------
- install_info* GetOTInstallInfo(void)
- {
- // DEBUG_BREAK("atmdlpi: GetOTInstallInfo:");
-
- return &theInstallInformation;
- }
-
- //-----------------------------------------------------------------------------------------
- // Description:
- // This routine is required and will only be called once. The routine must
- // call OTInitModule(). At this point Open Transport has made the decision to
- // use our card for a network connection. We must save the RegEntryID in case
- // we need it later. We should get the card assigned address and save
- // it in the dlpi private data area. The hw must be initialized and memory
- // allocated for dma buffers, install isrs, ....
- //
- // Open Transport will start calling our open, put, and service routines after
- // this routine if we return true.
- //
- // Input:
- // theID - node id of the card in the system registry
- //
- // Output:
- // true, if initialization was successful
- // false, if initialization failed
- //
- //-----------------------------------------------------------------------------------------
- Boolean InitStreamModule(RegEntryID *theID)
- {
- Boolean initOK;
- int j;
-
- // initOK = OTInitModule(); ****** These lines need to be present for OT 1.0 ******
- // if (initOK) { ****** These lines need to be present for OT 1.0 ******
-
- /* allocate memory and initiallize gPortPrivateData */
-
- gPortPrivateData = (PortPrivateData*) PoolAllocateResident(sizeof(PortPrivateData), kTrue);
- if (gPortPrivateData == NULL) {
- goto Terminate;
- }
-
- gPortPrivateData->port = 0; // use something similar to OTFindPortByDev(*dev, kATMName)
- gPortPrivateData->numCardOpens = 0;
- gPortPrivateData->nodeEntryID = *theID; // copy out Node Registry ID
-
- gPortPrivateData->minorDeviceTable
- = (MinorDeviceTableEntry**) PoolAllocateResident(sizeof(MinorDeviceTableEntry*) * MAX_MINORDEVICES, kTrue);
- if (gPortPrivateData->minorDeviceTable == NULL) {
- goto Terminate;
- }
- for (j=0; j < MAX_MINORDEVICES; j++)
- gPortPrivateData->minorDeviceTable[j] = 0;
-
- gPortPrivateData->connectTable
- = (ConnectTableEntry**) PoolAllocateResident(sizeof(ConnectTableEntry*) * MAX_CONNECTIONS, kTrue);
- if (gPortPrivateData->connectTable == NULL) {
- goto Terminate;
- }
- for (j=0; j < MAX_CONNECTIONS; j++)
- gPortPrivateData->connectTable[j] = 0;
- gPortPrivateData->maxConnectTableIndex = 0;
-
- initOK = ABCVendorInit(theID); // gDLPIPrivateData is set in this routine
-
- // was initialization successful?
- if (!initOK) {
- goto Terminate;
- }
-
- /* copy the ATM Physical address into the gPortPrivateData structure */
- ABCVendorGetFactoryATMAddress(gPortPrivateData->ourPhyAddress);
-
- /* copy the Peak Cell Rate into the gPortPrivateData structure */
- gPortPrivateData->ourPeakCellRate = ABCVendorGetPeakCellRate();
-
- /* zero out the current allocated peak rates */
- gPortPrivateData->currentFwdPeakCellRateAllocated = 0;
- gPortPrivateData->currentBwdPeakCellRateAllocated = 0;
-
- // }
-
- return initOK;
-
- Terminate:
- // OTTerminateModule(); ****** These lines need to be present for OT 1.0 ******
- initOK = false;
- return initOK;
- }
-
- //-----------------------------------------------------------------------------------------
- // Description:
- // This routine is required and will only be called when the driver is about to be
- // unloaded. At this point the driver is going away so we should close down
- // the hardware. If we get reopened then the InitStreamModule() will get called
- // again. The routine must call OTTerminateModule().
- //
- // Input:
- // NONE
- //
- // Output:
- // NONE
- //
- //-----------------------------------------------------------------------------------------
- void TerminateStreamModule(void)
- {
-
- if (gPortPrivateData->cardSpecific) {
- ABCVendorTerminate();
- gPortPrivateData->cardSpecific = NULL;
- }
-
- PoolDeallocate(gPortPrivateData->minorDeviceTable);
- PoolDeallocate(gPortPrivateData->connectTable);
-
- PoolDeallocate(gPortPrivateData);
-
- // OTTerminateModule(); ****** These lines need to be present for OT 1.0 ******
- }
-
- /***********************************************************
- *
- * ATM DRIVER DLPI : OPEN / CLOSE
- *
- ************************************************************/
-
- //-----------------------------------------------------------------------------------------
- // Description:
- // This routine is called each time a new stream is created. A
- // MinorDeviceTableEntry is allocated and then filled in accordingly.
- // A pointer to the MinorDeviceTableEntry is stored in the minorDevice
- // table of gPortPrivateData and also in the q_ptr field of the stream queue.
- //
- // Input:
- // rdq - read queue
- // dev - device number that consists of major and minor
- // flag - not currently used
- // sflag - indicates special open options
- // creds - not currently used
- //
- // Output:
- // kOTNoError, if no problem occurred
- // error, if no memory or the client tried to open as a module instead of cloneopen
- //
- //-----------------------------------------------------------------------------------------
- static int atm_open(queue_t* rdq, dev_t* dev, int flag, int sflag, cred_t* creds)
- {
- OSStatus err;
- size_t idx;
- MinorDeviceTableEntry* theMinorDev;
- UInt8 addressArray[kATMPhysicalAddressLength];
-
- // DEBUG_BREAK("atmdlpi: atm_open:");
-
- /*
- * Make sure caller is properly credentialed
- */
- if ( (err = drv_priv(creds)) != kOTNoError )
- return err;
- /*
- * If we're being reopened - just return
- */
- if ( rdq->q_ptr != NULL )
- return kOTNoError;
- /*
- * Make sure we're being opened properly - We only allow
- * a "clone" open.
- */
- if ( sflag != CLONEOPEN )
- return EINVAL;
-
- /*
- * Record the number of clients for this card
- */
- gPortPrivateData->numCardOpens++;
-
- /*
- * Find a minor number we can use
- */
- for (idx = 0; idx < MAX_MINORDEVICES; ++idx)
- if ( gPortPrivateData->minorDeviceTable[idx] == 0 )
- break;
- /*
- * If we're out of minor numbers - return an error
- */
-
- if ( idx >= MAX_MINORDEVICES )
- return ENOMEM;
-
- theMinorDev = gPortPrivateData->minorDeviceTable[idx]
- = (MinorDeviceTableEntry*) PoolAllocateResident(sizeof(MinorDeviceTableEntry), kTrue);
-
- theMinorDev->minorTableIndex = idx;
- theMinorDev->minorNum = idx + kFirstMinorNumber;
- theMinorDev->dlstate = DL_UNBOUND;
- theMinorDev->rdq = (queue_t *) rdq;
- theMinorDev->numConnections = 0;
- theMinorDev->useUDInd = 0;
- theMinorDev->firstConnection = (ConnectTableEntry *)0;
-
- /*
- * Set our device number so STREAMS knows what we are
- */
- *dev = makedevice(getemajor(*dev), idx + kFirstMinorNumber);
-
- rdq->q_ptr = (void *) theMinorDev;
- WR(rdq)->q_ptr = rdq->q_ptr;
-
- /*
- * return no error
- */
- return kOTNoError;
- }
-
- //-----------------------------------------------------------------------------------------
- // Description:
- // This routine closes a stream. All VCs are disconnected and then
- // the memory for the MinorDeviceTableEntry is deallocated.
- //
- // Input:
- // rdq - read queue
- // flag - not currently used
- // creds - not currently used
- //
- // Output:
- // always return kOTNoError
- //
- //-----------------------------------------------------------------------------------------
- static int atm_close(queue_t* rdq, int flag, cred_t* creds)
- {
- MinorDeviceTableEntry* theMinorDev = (MinorDeviceTableEntry *) rdq->q_ptr;
- OSStatus err;
-
- if (theMinorDev == NULL) {
- ERROR_BREAK("atmdlpi: atm_close: null q_ptr\n");
- return ENXIO;
- }
-
- /* remove any timer call */
- if (theMinorDev->idType == kdlpiBufcallType)
- unbufcall(theMinorDev->timeoutID);
- // else if (theMinorDev->idType == kdlpiTimerType)
- // untimeout(theMinorDev->timeoutID);
-
- err = disconnect_all_pvc(theMinorDev);
- rdq->q_ptr = NULL;
- WR(rdq)->q_ptr = NULL;
-
- /*
- * Free my minor number and the firstConnection
- * Zero out the q_ptr. If we allocated any memory and stored
- * it there, now would be a good time to free it!
- */
- gPortPrivateData->minorDeviceTable[theMinorDev->minorTableIndex] = 0;
- PoolDeallocate(theMinorDev);
-
- gPortPrivateData->numCardOpens--;
-
- /*
- * Return no error
- */
- return kOTNoError;
- }
-
- /***********************************************************
- *
- * ATM DRIVER DLPI : WRITE SIDE
- *
- ************************************************************/
-
- //-----------------------------------------------------------------------------------------
- // Description:
- // This routine is called when someone wants to put something on our write queue.
- // Somethings are handled immediately and some are put on the write queue and
- // then serviced during the write service routine. If a message is received that
- // the driver is not expecting then it is dropped on the floor.
- //
- // Input:
- // q - the write queue
- // mp - message that we need to process
- //
- // Output:
- // returns true
- //
- //-----------------------------------------------------------------------------------------
- static int atm_wput(queue_t* q, mblk_t* mp)
- {
- union DL_primitives *dlp;
- UInt32 prim;
-
- MinorDeviceTableEntry* theMinorDev = (MinorDeviceTableEntry *) q->q_ptr;
-
- // DEBUG_BREAK("atmdlpi: atm_wput: ");
-
- // DUMP_DLPI_MSG(mp);
-
- if (theMinorDev == NULL) {
- ERROR_BREAK("atmdlpi: atm_wput: null q_ptr\n");
- return ENXIO;
- }
-
- switch (mp->b_datap->db_type) {
- case M_DATA:
- {
- /*
- * Handle M_DATAs really fast !
- */
- if ((qsize(q)) ||
- (ATMDLPI_unitdata_req(theMinorDev, mp, 1 /* use default PVC */)==kdlpiRETRY) )
- putq(q, mp);
-
- break;
- }
-
- case M_PROTO:
- case M_PCPROTO:
- dlp = (union DL_primitives *)mp->b_rptr;
- prim = dlp->dl_primitive;
- if (prim == DL_UNITDATA_REQ) {
-
- /*
- * Handle DL_UNITDATA_REQs really fast !
- */
- if ((qsize(q)) ||
- (ATMDLPI_unitdata_req(theMinorDev, mp, 0 /* get PVC from message */)==kdlpiRETRY) )
- putq(q, mp);
- }
- /* All other messages go on to the queue */
- else
- putq(q, mp);
- break;
-
- case M_IOCTL:
- atm_ioctl(q, mp);
- break;
-
- case M_FLUSH:
- atm_flush(q, mp);
- break;
-
- case M_COPYIN:
- case M_COPYOUT:
- case M_ERROR:
- case M_HANGUP:
- case M_IOCACK:
- case M_IOCNAK:
- case M_PCSIG:
- case M_HPDATA:
- case M_STOP:
- case M_START:
- case M_STOPI:
- case M_STARTI:
- case M_READ:
- case M_SETOPTS:
- case M_SIG:
- case M_BREAK:
- case M_DELAY:
- case M_CTL:
- case M_PASSFP:
- case M_RSE:
- freemsg(mp);
- break;
-
- default:
- ERROR_SPRINTF((tempstr,"atmdlpi: atm_wput: Bad mesg type, %x %d\n", mp->b_datap->db_type,*mp->b_rptr));
- ERROR_BREAK(tempstr);
- freemsg(mp);
- break;
- }
-
- return kOTNoError;
- }
-
- //-----------------------------------------------------------------------------------------
- // Description:
- // This routine handles everything that was deferred (put on the write queue) during
- // the write put routine. This routine dequeues DLPI messages from the write queue and
- // processes them. If a message is not supported
- // then an error ack is sent to the client.
- //
- // Input:
- // q - the write queue
- //
- // Output:
- // returns kOTNoError
- //
- //-----------------------------------------------------------------------------------------
- static int atm_wsrv(queue_t* q)
- {
- mblk_t* mp;
- UInt32 err, prim;
- union DL_primitives *dlp;
-
- MinorDeviceTableEntry* theMinorDev = (MinorDeviceTableEntry *) q->q_ptr;
-
- // DEBUG_BREAK("atmdlpi: atm_wsrv: ");
-
- if (theMinorDev == NULL) {
- ERROR_BREAK("atmdlpi: null q_ptr\n");
- return ENXIO;
- }
-
- /* there should be only M_PROTO/PCPROTO messages here */
-
- while ( (mp = getq(q)) != NULL ) {
-
- // DUMP_DLPI_MSG(mp);
-
- if (mp->b_datap->db_type==M_DATA) {
- if (ATMDLPI_unitdata_req(theMinorDev, mp, 1 /* use default PVC */)==kdlpiRETRY) {
- putbq(q, mp);
- return kOTNoError;
- }
- }
- else if ( mp->b_datap->db_type==M_PROTO || mp->b_datap->db_type==M_PCPROTO) {
-
- /* HANDLE ATM DLPI MESSAGES */
-
- err = 0;
- dlp = (union DL_primitives *) mp->b_rptr;
- prim = dlp->dl_primitive;
- switch (prim) {
-
- case DL_UNITDATA_REQ:
- ERROR_BREAK("atmdlpi: atm_wsrv: DL_UNITDATA_REQ because card transmit is flow controlled\n");
- if (ATMDLPI_unitdata_req(theMinorDev, mp, 0 /* get PVC from message */)==kdlpiRETRY) {
- putbq(q, mp);
- return kOTNoError;
- }
- break;
-
- case DL_INFO_REQ:
- if (ATMDLPI_info_req(theMinorDev, mp) != kdlpiDONE)
- ERROR_BREAK("atmdlpi: atm_wsrv: can't respond to DL_INFO_REQ");
- freemsg(mp);
- break;
-
- case DL_BIND_REQ:
- if (ATMDLPI_bind_req(theMinorDev, mp) == kdlpiRETRY) {
- putbq(q, mp);
- return kOTNoError;
- }
- break;
-
- case DL_UNBIND_REQ:
- if (ATMDLPI_unbind_req(theMinorDev, mp) == kdlpiRETRY) {
- putbq(q, mp);
- return kOTNoError;
- }
- break;
-
- case DL_CONNECT_REQ:
- if (ATMDLPI_connect_req(theMinorDev, mp) == kdlpiRETRY) {
- putbq(q, mp);
- return kOTNoError;
- }
- break;
-
- case DL_DISCONNECT_REQ:
- if (ATMDLPI_disconnect_req(theMinorDev, mp) == kdlpiRETRY) {
- putbq(q, mp);
- return kOTNoError;
- }
- break;
-
- case DL_UDQOS_REQ:
- if (ATMDLPI_udqos_req(theMinorDev, mp)== kdlpiRETRY) {
- putbq(q, mp);
- return kOTNoError;
- }
- break;
-
- case DL_PHYS_ADDR_REQ:
- if (ATMDLPI_phy_addr_req(theMinorDev, mp)== kdlpiRETRY) {
- putbq(q, mp);
- return kOTNoError;
- }
- break;
-
- case DL_SET_PHYS_ADDR_REQ:
- if (ATMDLPI_set_phy_addr_req(theMinorDev, mp)== kdlpiRETRY) {
- putbq(q, mp);
- return kOTNoError;
- }
- break;
-
- case DL_SUBS_BIND_REQ:
- case DL_SUBS_UNBIND_REQ:
- case DL_ATTACH_REQ:
- case DL_DETACH_REQ:
- case DL_ENABMULTI_REQ:
- case DL_XID_REQ:
- case DL_XID_RES:
- case DL_TEST_REQ:
- case DL_TEST_RES:
- case DL_PROMISCON_REQ:
- case DL_PROMISCOFF_REQ:
- case DL_CONNECT_RES:
- case DL_TOKEN_REQ:
- case DL_RESET_REQ:
- case DL_RESET_RES:
- case DL_DATA_ACK_REQ:
- case DL_REPLY_REQ:
- case DL_REPLY_UPDATE_REQ:
- err = DL_NOTSUPPORTED; /* fall through */
-
- default:
- if (err == 0)
- err = DL_BADPRIM;
- (void) ATMDLPI_error_ack(theMinorDev, mp, prim, err, 0);
- break;
- }
- }
- else {
- ERROR_SPRINTF((tempstr,"atmdlpi: atm_wsrv: Bad mesg type, %x %d\n", mp->b_datap->db_type,*mp->b_rptr));
- ERROR_BREAK(tempstr);
- freemsg(mp);
- }
- }
- return kOTNoError;
- }
-
-
- /***********************************************************
- *
- * ATM DRIVER DLPI : READ SIDE
- *
- ************************************************************/
-
- //-----------------------------------------------------------------------------------------
- // Description:
- // This routine is called when someone wants to put something on our read queue.
- // Something is drastically wrong if this ever gets called.
- //
- // Input:
- // q - the read queue
- // mp - message that we need to process
- //
- // Output:
- // returns true
- //
- //-----------------------------------------------------------------------------------------
- static int atm_rput(queue_t* q, mblk_t* mp)
- {
- ERROR_BREAK("atmdlpi: atm_rput: should never get called");
- return EINVAL;
- }
-
- //-----------------------------------------------------------------------------------------
- // Description:
- // This routine handles everything that was deferred (put on the read queue) when
- // flow control was experienced in the upward direction.
- //
- // Input:
- // q - the read queue
- //
- // Output:
- // returns kOTNoError
- //
- //-----------------------------------------------------------------------------------------
- static int atm_rsrv(queue_t* q)
- {
- mblk_t* mp;
-
- // DEBUG_BREAK("atmdlpi: atm_rsrv: ");
-
- /*
- * We know that only M_PROTO (DL_UNITDATA_IND) and M_DATA messages are on the queue,
- * since that is all that we scheduled.
- */
- while ( (mp = getq(q)) != NULL )
- {
-
- DEBUG_BREAK("atmdlpi: atm_rsrv: got a queued message");
- // DUMP_DLPI_MSG(mp);
-
- /*
- * If we're flow controlled, get out and we'll come back when the flow-
- * control lifts.
- */
- if ( !bcanput(q->q_next, mp->b_band) ) {
- // DEBUG_SPRINTF((tempstr,"atmdlpi: atm_rsrv: q above is full %d\n", q->q_next->q_count));
- // DEBUG_BREAK(tempstr);
- putbq(q, mp);
- return kOTNoError;
- }
- /*
- * Otherwise, send the data upstream, and get some more
- */
- putnext(q, mp);
- }
- }
-
- /***********************************************************
- *
- * ATM DRIVER DLPI : IOCTL HANDLING
- *
- ************************************************************/
-
- //-----------------------------------------------------------------------------------------
- // Description:
- // This routine handles all the ioctl calls made to the driver. Currently only
- // the DL_IOC_SUBS_CONNECT and the DL_IOC_SUBS_DISCONNECT are handled.
- //
- // Input:
- // q - the write queue
- // mp - the message block that contains ioctl parameters
- //
- // Output:
- // NONE
- //
- //-----------------------------------------------------------------------------------------
- static void atm_ioctl(queue_t* q, mblk_t* mp)
- {
- struct iocblk* iocp = (struct iocblk*) mp->b_rptr;
- MinorDeviceTableEntry* theMinorDev = (MinorDeviceTableEntry *) q->q_ptr;
- OSStatus err;
-
- // DEBUG_BREAK("atmdlpi: atm_ioctl: ");
-
-
- if (!mp->b_cont) {
- mp->b_datap->db_type = M_IOCNAK;
- iocp->ioc_error = EINVAL;
- iocp->ioc_rval = 0;
- }
- else {
- switch (iocp->ioc_cmd) {
- case DL_IOC_SUBS_CONNECT:
- err = ATMDLPI_IOCTL_subs_connect(theMinorDev, mp);
- if (err)
- ERROR_BREAK("atmdlpi: atm_ioctl: could not complete ATMDLPI_IOCTL_subs_connect");
- mp->b_datap->db_type = M_IOCACK;
- iocp->ioc_error = err;
- iocp->ioc_rval = 0;
- break;
-
- case DL_IOC_SUBS_DISCONNECT:
- err = ATMDLPI_IOCTL_subs_disconnect(theMinorDev, mp);
- if (err)
- ERROR_BREAK("atmdlpi: atm_ioctl: could not complete ATMDLPI_IOCTL_subs_disconnect");
- mp->b_datap->db_type = M_IOCACK;
- iocp->ioc_error = err;
- iocp->ioc_rval = 0;
- break;
-
- default:
- mp->b_datap->db_type = M_IOCNAK;
- iocp->ioc_count = 0;
- iocp->ioc_error = EINVAL;
- iocp->ioc_rval = 0;
- }
- }
-
- qreply(q, mp);
-
- return;
- }
-
- /***********************************************************
- *
- * ATM DRIVER DLPI : FLUSH HANDLING
- *
- ************************************************************/
-
- //-----------------------------------------------------------------------------------------
- // Description:
- // This routine receives the flush call and then it must send it up the read
- // side of the stream.
- //
- // Input:
- // q - the write queue
- // mp - the message block that contains the flush parameters
- //
- // Output:
- // NONE
- //
- //-----------------------------------------------------------------------------------------
- static void atm_flush(queue_t* q, mblk_t* mp)
- {
-
- DEBUG_BREAK("atmdlpi: atm_flush:");
-
- if ( mp->b_rptr[0] & FLUSHW) {
- if ( (mp->b_rptr[0] & FLUSHBAND) && mp->b_wptr - mp->b_rptr == 2 )
- flushband(q, mp->b_rptr[1], FLUSHALL);
- else
- flushq(q, FLUSHALL);
- }
- if ( mp->b_rptr[0] & FLUSHR ) {
- if ( (mp->b_rptr[0] & FLUSHBAND) && mp->b_wptr - mp->b_rptr == 2 )
- flushband(RD(q), mp->b_rptr[1], FLUSHALL);
- else
- flushq(RD(q), FLUSHALL);
- mp->b_rptr[0] &= ~FLUSHW;
- qreply(q, mp);
- return;
- }
- return;
- }
-
- /***********************************************************
- *
- * ATM DRIVER DLPI : DLPI Message Handling
- *
- ************************************************************/
-
- //-----------------------------------------------------------------------------------------
- // reply to DL_INFO_REQ (DL_INFO_ACK generation)
- //-----------------------------------------------------------------------------------------
-
- static int ATMDLPI_info_req(MinorDeviceTableEntry* minorDev, mblk_t* mp)
- {
- mblk_t* ack_mp;
- dl_info_ack_t* ackp;
- PVCAddress* pvc;
- ATMSimpleQOS* simpleQOS;
- ATMVCParams* connParams;
- ATMSimpleQOS* simpleQOSRange;
-
- // DEBUG_BREAK("atmdlpi: ATMDLPI_info_req:");
-
- if ((ack_mp = allocb(sizeof(dl_info_ack_t) + sizeof(PVCAddress) + 2 * sizeof(ATMSimpleQOS),
- BPRI_LO)) == NULL) {
- ERROR_BREAK("Atm info ack allocb failed");
- // schedule_write_queue(minorDev, sizeof(dl_info_ack_t));
- return kdlpiRETRY;
- }
-
- ack_mp->b_datap->db_type = M_PCPROTO;
- ackp = (dl_info_ack_t *) ack_mp->b_wptr;
- ackp->dl_primitive = DL_INFO_ACK;
- ackp->dl_max_sdu = kMaxAAL5PDU;
- ackp->dl_min_sdu = kMinAAL5PDU;
- ackp->dl_mac_type = DL_OTHER;
- ackp->dl_reserved = 0;
- ackp->dl_sap_length = 0;
- ackp->dl_service_mode = DL_CODLS;
- ackp->dl_addr_length = sizeof(PVCAddress);
- ackp->dl_addr_offset = sizeof(dl_info_ack_t);
- ackp->dl_qos_length = sizeof(ATMSimpleQOS);
- ackp->dl_qos_offset = ackp->dl_addr_offset + ackp->dl_addr_length;
- ackp->dl_qos_range_length = sizeof(ATMSimpleQOS);
- ackp->dl_qos_range_offset = ackp->dl_qos_offset + ackp->dl_qos_length;
- ackp->dl_provider_style = DL_STYLE1;
- ackp->dl_version = DL_VERSION_2;
- ackp->dl_brdcst_addr_length = 0;
- ackp->dl_brdcst_addr_offset = DL_UNKNOWN;
- ackp->dl_growth = 0;
- ackp->dl_current_state = minorDev->dlstate;
-
- ack_mp->b_wptr += sizeof(dl_info_ack_t);
-
- pvc = (PVCAddress*) ack_mp->b_rptr + ackp->dl_addr_offset;
- *pvc = minorDev->firstConnection->pvc;
-
- ack_mp->b_wptr += ackp->dl_addr_length;
-
- simpleQOS = (ATMSimpleQOS*) (ack_mp->b_rptr + ackp->dl_qos_offset);
- simpleQOS->dl_qos_type = DL_QOS_SIMPLE_ATM;
- connParams = &(simpleQOS->params);
- connParams->aal = minorDev->firstConnection->aal;
- connParams->traffic = minorDev->firstConnection->traffic;
- connParams->qos = minorDev->firstConnection->qos;
-
- ack_mp->b_wptr += ackp->dl_qos_length;
-
- simpleQOSRange = (ATMSimpleQOS*) (ack_mp->b_rptr + ackp->dl_qos_range_offset);
- simpleQOSRange->dl_qos_type = DL_QOS_SIMPLE_ATM_RANGE;
- connParams = &(simpleQOSRange->params);
- connParams->traffic.fwdPeakCellRate01 = gPortPrivateData->ourPeakCellRate;
- connParams->traffic.bwdPeakCellRate01 = gPortPrivateData->ourPeakCellRate;
-
- ack_mp->b_wptr += ackp->dl_qos_range_length;
-
- putnext(minorDev->rdq, ack_mp);
-
- return kdlpiDONE;
- }
-
- //-----------------------------------------------------------------------------------------
- // DL_PHYS_ADDR_REQ handling
- //-----------------------------------------------------------------------------------------
-
- static int ATMDLPI_phy_addr_req(MinorDeviceTableEntry* minorDev, mblk_t* mp)
- {
- mblk_t *ack_mp;
- dl_phys_addr_ack_t *ackp;
- dl_phys_addr_req_t *addrReq = (dl_phys_addr_req_t *) mp->b_rptr;
- UInt8 addressArray[kATMPhysicalAddressLength];
-
- if ((ack_mp = allocb(sizeof(dl_phys_addr_ack_t) + kATMPhysicalAddressLength, BPRI_HI)) == NULL) {
- schedule_write_queue(minorDev, DL_PHYS_ADDR_ACK_SIZE + kATMPhysicalAddressLength);
- return kdlpiRETRY;
- }
-
- ack_mp->b_datap->db_type = M_PCPROTO;
- ackp = (dl_phys_addr_ack_t *)ack_mp->b_wptr;
- ackp->dl_primitive = DL_PHYS_ADDR_ACK;
- ackp->dl_addr_length = kATMPhysicalAddressLength;
- ackp->dl_addr_offset = sizeof(dl_phys_addr_ack_t);
- ack_mp->b_wptr += sizeof(dl_phys_addr_ack_t) + kATMPhysicalAddressLength;
- switch(addrReq->dl_addr_type) {
- case DL_CURR_PHYS_ADDR:
- OTCopy48BitAddress(gPortPrivateData->ourPhyAddress,
- ack_mp->b_rptr + ackp->dl_addr_offset);
- break;
- case DL_FACT_PHYS_ADDR:
- ABCVendorGetFactoryATMAddress(addressArray);
- OTCopy48BitAddress(addressArray, ack_mp->b_rptr + ackp->dl_addr_offset);
- break;
- default:
- break;
- }
-
- freemsg(mp);
-
- putnext(minorDev->rdq, ack_mp);
-
- return kdlpiDONE;
- }
-
- static int all_minors_unbound()
- {
- int idx;
-
- for (idx = 0; idx < MAX_MINORDEVICES; ++idx)
- if ( (gPortPrivateData->minorDeviceTable[idx] != 0) && gPortPrivateData->minorDeviceTable[idx]->dlstate!=DL_UNBOUND)
- break;
-
- if ( idx >= MAX_MINORDEVICES )
- return 0;
- else
- return 1;
- }
-
- //-----------------------------------------------------------------------------------------
- // DL_SET_PHYS_ADDR_REQ handling
- //-----------------------------------------------------------------------------------------
-
- static int ATMDLPI_set_phy_addr_req(MinorDeviceTableEntry* minorDev, mblk_t* mp)
- {
- dl_set_phys_addr_req_t *req = (dl_set_phys_addr_req_t *)mp->b_rptr;
- SInt32 length = req->dl_addr_length;
- mblk_t *ack_mp;
- UInt8 *physicalAddress = ((UInt8 *)req) + req->dl_addr_offset;
-
- // all streams must be unbound, if error abort
- if (!all_minors_unbound()) {
- ATMDLPI_error_ack(minorDev, mp, DL_SET_PHYS_ADDR_REQ, DL_OUTSTATE, 0);
- return kdlpiDONE;
- }
-
- // must only contain ATM address
- if (length != kATMPhysicalAddressLength) {
- ATMDLPI_error_ack(minorDev, mp, DL_SET_PHYS_ADDR_REQ, DL_BADADDR, 0);
- return kdlpiDONE;
- }
-
- if ((ack_mp = allocb(DL_OK_ACK_SIZE, BPRI_HI)) == NULL) {
- schedule_write_queue(minorDev, DL_OK_ACK_SIZE);
- return kdlpiRETRY;
- }
-
- OTCopy48BitAddress(physicalAddress, gPortPrivateData->ourPhyAddress);
- ABCVendorSetATMAddress(physicalAddress);
-
- (void) ATMDLPI_ok_ack(minorDev, mp, DL_SET_PHYS_ADDR_REQ);
-
- return kdlpiDONE;
- }
-
- //-----------------------------------------------------------------------------------------
- // DL_BIND_REQ handling
- //-----------------------------------------------------------------------------------------
-
- static int ATMDLPI_bind_req(MinorDeviceTableEntry* minorDev, mblk_t* mp)
- {
- dl_bind_req_t *req = (dl_bind_req_t *) mp->b_rptr;
- UInt16 dlsap = (UInt16)req->dl_sap;
- dl_bind_ack_t *ackp = (dl_bind_ack_t *) mp->b_rptr;
-
- // DEBUG_BREAK("atmdlpi: ATMDLPI_bind_req:");
-
- if (req->dl_service_mode != DL_CODLS) {
- (void) ATMDLPI_error_ack(minorDev, mp, DL_BIND_REQ, DL_UNSUPPORTED, 0);
- return kdlpiDONE;
- }
-
- if (minorDev->dlstate != DL_UNBOUND) {
- (void) ATMDLPI_error_ack(minorDev, mp, DL_BIND_REQ, DL_OUTSTATE, 0);
- return kdlpiDONE;
- }
-
- mp->b_wptr = mp->b_rptr;
-
- mp->b_datap->db_type = M_PCPROTO;
- ackp->dl_primitive = DL_BIND_ACK;
- ackp->dl_sap = req->dl_sap;
- ackp->dl_addr_length = 0;
- ackp->dl_addr_offset = DL_BIND_ACK_SIZE;
- ackp->dl_max_conind = 0;
- ackp->dl_xidtest_flg = 0;
- mp->b_wptr += DL_BIND_ACK_SIZE;
-
- minorDev->dlstate = DL_IDLE;
-
- putnext(minorDev->rdq, mp);
- return kdlpiDONE;
- }
-
- //-----------------------------------------------------------------------------------------
- // DL_UNBIND_REQ handling
- //-----------------------------------------------------------------------------------------
-
- static int ATMDLPI_unbind_req(MinorDeviceTableEntry* minorDev, mblk_t* mp)
- {
-
- // DEBUG_BREAK("atmdlpi: ATMDLPI_unbind_req:");
-
- if (minorDev->dlstate != DL_IDLE) {
- (void) ATMDLPI_error_ack(minorDev, mp, DL_UNBIND_REQ, DL_OUTSTATE, 0);
- return kdlpiDONE;
- }
-
- minorDev->dlstate = DL_UNBOUND;
-
- (void) ATMDLPI_ok_ack(minorDev, mp, DL_UNBIND_REQ);
-
- return kdlpiDONE;
- }
-
- //-----------------------------------------------------------------------------------------
- // ATMVCParams Validation
- //-----------------------------------------------------------------------------------------
-
- static int validate_pvc(PVCAddress* pvc)
- {
- if ( (pvc->addressType != kPVCAddressType) ||
- (pvc->vpi > 255) ||
- (pvc->vci == 0) ) {
- ERROR_BREAK("atmdlpi: validate_pvc: invalid");
- return 0;
- }
- else
- return 1;
-
- }
-
- //-----------------------------------------------------------------------------------------
- // AALType validation
- //-----------------------------------------------------------------------------------------
- static int validate_aal(AALType aal)
- {
- switch (aal) {
- case kAALType34:
- case kAALType5:
- return 1;
-
- case kAALTypeNull:
- case kAALType1:
- case kAALType2:
- case kAALTypeUser:
- default:
- ERROR_BREAK("atmdlpi: validate_aal: invalid");
- return 0;
- }
- }
-
- //-----------------------------------------------------------------------------------------
- // TrafficDec validation
- //-----------------------------------------------------------------------------------------
- static int validate_traffic(TrafficDesc* traffic)
- {
- if (traffic->bstEffortReq) return 1;
-
- if ( (gPortPrivateData->currentFwdPeakCellRateAllocated + traffic->fwdPeakCellRate01 > gPortPrivateData->ourPeakCellRate) ||
- (gPortPrivateData->currentBwdPeakCellRateAllocated + traffic->bwdPeakCellRate01 > gPortPrivateData->ourPeakCellRate) )
- {
- ERROR_BREAK("atmdlpi: validate_traffic: invalid");
- return 0;
- }
- else
- return 1;
- }
-
- //-----------------------------------------------------------------------------------------
- // QOSClass validation
- //-----------------------------------------------------------------------------------------
- static int validate_qos(QOSClass qos)
- {
- return 1;
- }
-
- //-----------------------------------------------------------------------------------------
- // DL_CONNECT_REQ handling
- //-----------------------------------------------------------------------------------------
-
- static int ATMDLPI_connect_req(MinorDeviceTableEntry* minorDev, mblk_t* mp)
- {
- union DL_primitives* dp = (union DL_primitives*) mp->b_rptr;
- ConnectTableEntry* conn;
- UInt32 idx;
- OSStatus err;
- PVCAddress* pvc;
- ATMVCParams* connParams;
- ATMSimpleQOS* simpleQOS;
- UInt32 flags;
- UInt32 peak_Kilocells;
-
- // DEBUG_BREAK("atmdlpi: ATMDLPI_connect_req:");
-
- if (minorDev->dlstate != DL_IDLE) {
- (void) ATMDLPI_error_ack(minorDev, mp, DL_CONNECT_REQ, DL_OUTSTATE, 0);
- return kdlpiDONE;
- }
-
- pvc = (PVCAddress*) (mp->b_rptr + ((dl_connect_req_t*) dp)->dl_dest_addr_offset);
- simpleQOS = (ATMSimpleQOS*) (mp->b_rptr + ((dl_connect_req_t*) dp)->dl_qos_offset);
- if (simpleQOS->dl_qos_type != DL_QOS_SIMPLE_ATM) {
- ERROR_BREAK("atmdlpi: ATMDLPI_connect_req: dl_qos_type != DL_QOS_SIMPLE_ATM");
- (void) ATMDLPI_error_ack(minorDev, mp, DL_CONNECT_REQ, DL_BADADDR, 0);
- return kdlpiDONE;
- }
- connParams = &(simpleQOS->params);
-
- flags = connParams->traffic.fwdPeakCellRate01 > 0 ? kVCIOut : 0;
- flags |= connParams->traffic.bwdPeakCellRate01 > 0 ? kVCIIn : 0;
- if ( (!validate_pvc(pvc)) ||
- (find_connection(pvc->vpi, pvc->vci, flags) != NULL) ||
- (!validate_aal(connParams->aal)) ||
- (!validate_traffic(&(connParams->traffic) )) ||
- (!validate_qos(connParams->qos)) ) {
- ERROR_SPRINTF((tempstr,"atmdlpi: ATMDLPI_connect_req: vpi,vci %u,%u can not be accepted\n", pvc->vpi, pvc->vci));
- ERROR_BREAK(tempstr);
- (void) ATMDLPI_error_ack(minorDev, mp, DL_CONNECT_REQ, DL_BADADDR, 0);
- return kdlpiDONE;
- }
-
- /*
- * Allocate and store a free connection table entry.
- */
- for (idx = 0; idx < MAX_CONNECTIONS; ++idx)
- if (gPortPrivateData->connectTable[idx]==0) break;
- if ( idx >= MAX_CONNECTIONS ) {
- ERROR_BREAK("atmdlpi: ATMDLPI_connect_req: connection table full\n");
- (void) ATMDLPI_error_ack(minorDev, mp, DL_CONNECT_REQ, DL_SYSERR, ENOMEM);
- return kdlpiDONE;
- }
-
- minorDev->numConnections++;
-
- /*
- * Look up the connection table entry
- */
- minorDev->firstConnection = gPortPrivateData->connectTable[idx] = conn
- = (ConnectTableEntry*) OTAllocMem(sizeof(ConnectTableEntry));
- if (idx > gPortPrivateData->maxConnectTableIndex) gPortPrivateData->maxConnectTableIndex = idx;
-
- /*
- * assign values from the connect_req message into
- * local storage.
- */
- conn->connectTableIndex = idx;
- conn->rdq = minorDev->rdq;
- conn->parentMinorDevice = minorDev;
- conn->nextConnection = (ConnectTableEntry*) 0;
- conn->prevConnection = (ConnectTableEntry*) 0;
- conn->pvc = *pvc;
- conn->aal = connParams->aal;
- conn->qos = connParams->qos;
- conn->traffic = connParams->traffic;
- conn->flags = flags;
-
- /* bump up the current peak rates allocated */
- if (!connParams->traffic.bstEffortReq) {
- gPortPrivateData->currentFwdPeakCellRateAllocated += connParams->traffic.fwdPeakCellRate01;
- gPortPrivateData->currentBwdPeakCellRateAllocated += connParams->traffic.bwdPeakCellRate01;
- }
-
- /* Activate an incoming vci, some cards need to activate outgoing vci too */
- if (conn->flags & kVCIIn) {
-
- err = ABCVendorActivateVCI(conn);
- if (err) {
- ERROR_SPRINTF((tempstr,"atmdlpi: ATMDLPI_connect_req: ABCVendorActivateVCI returned error %d\n", err));
- ERROR_BREAK(tempstr);
- (void) ATMDLPI_error_ack(minorDev, mp, DL_CONNECT_REQ, DL_BADADDR, 0);
- return kdlpiDONE;
- }
- }
-
- minorDev->dlstate = DL_DATAXFER;
-
- dp = (union DL_primitives *) mp->b_rptr;
- dp->dl_primitive = DL_CONNECT_CON;
- mp->b_datap->db_type = M_PROTO;
-
- putnext(minorDev->rdq, mp);
-
- return kdlpiDONE;
- }
-
- //-----------------------------------------------------------------------------------------
- // DL_DISCONNECT_REQ handling
- //-----------------------------------------------------------------------------------------
-
- static int ATMDLPI_disconnect_req(MinorDeviceTableEntry* minorDev, mblk_t* mp)
- {
- OSStatus err;
-
-
- // DEBUG_BREAK("atmdlpi: ATMDLPI_disconnect_req:");
-
- if (minorDev->dlstate != DL_DATAXFER) {
- (void) ATMDLPI_error_ack(minorDev, mp, DL_DISCONNECT_REQ, DL_OUTSTATE, 0);
- return kdlpiDONE;
- }
-
- err = disconnect_all_pvc(minorDev);
-
- if ((err==0) && (minorDev->numConnections==0)) {
- minorDev->dlstate = DL_IDLE;
- (void) ATMDLPI_ok_ack(minorDev, mp, DL_DISCONNECT_REQ);
- }
- else
- (void) ATMDLPI_error_ack(minorDev, mp, DL_DISCONNECT_REQ, DL_SYSERR, -1);
-
-
- return kdlpiDONE;
- }
-
- //-----------------------------------------------------------------------------------------
- // Disconnect all PVCs and reset all ConnectTableEntry
- //-----------------------------------------------------------------------------------------
-
- static int disconnect_all_pvc(MinorDeviceTableEntry* minorDev)
- {
- ConnectTableEntry* conn;
- OSStatus err = 0;
-
-
- // DEBUG_BREAK("atmdlpi: disconnect_all_pvc:");
-
- conn = minorDev->firstConnection;
-
- if ((minorDev->numConnections>0) && (conn!=NULL)) {
- ConnectTableEntry* curr_con = minorDev->firstConnection;
- ConnectTableEntry* next_con;
-
- while (curr_con != NULL) {
- next_con = curr_con->nextConnection;
- err += disconnect_pvc(minorDev, curr_con);
- curr_con = next_con;
- }
- }
-
- return err;
- }
-
- //-----------------------------------------------------------------------------------------
- // Disconnect a PVC and reset a ConnectTableEntry
- //-----------------------------------------------------------------------------------------
-
- static int disconnect_pvc(MinorDeviceTableEntry* minorDev, ConnectTableEntry* conn)
- {
- OSStatus err = kOTNoError;
-
- /* Deactivate an incoming vci, some cards need to activate outgoing vci too */
- if (conn->flags & kVCIIn) {
-
- err = ABCVendorDeactivateVCI(conn);
- if (err) {
- ERROR_SPRINTF((tempstr,"atmdlpi: disconnect_pvc: ABCVendorDeactivateVCI returned error %d\n", err));
- ERROR_BREAK(tempstr);
- return err;
- }
- }
-
- /* bump down the peak rates allocated */
- if (!conn->traffic.bstEffortReq) {
- gPortPrivateData->currentFwdPeakCellRateAllocated -= conn->traffic.fwdPeakCellRate01;
- gPortPrivateData->currentBwdPeakCellRateAllocated -= conn->traffic.bwdPeakCellRate01;
- }
-
- /* reset the relevant places in the MinorDeviceTable
- and the ConnectTable */
- if (conn->prevConnection)
- conn->prevConnection->nextConnection = conn->nextConnection;
- if (conn->nextConnection)
- conn->nextConnection->prevConnection = conn->prevConnection;
-
- gPortPrivateData->connectTable[conn->connectTableIndex] = 0;
- OTFreeMem((void*) conn);
-
- minorDev->numConnections--;
-
- if (minorDev->numConnections==0)
- minorDev->firstConnection = (ConnectTableEntry *) 0;
-
- return err;
- }
-
- //-----------------------------------------------------------------------------------------
- // ATMDLPI_SUBS_CONNECT Ioctl handling
- //-----------------------------------------------------------------------------------------
-
- static int ATMDLPI_IOCTL_subs_connect(MinorDeviceTableEntry* minorDev, mblk_t* mp)
- {
- ConnectTableEntry* conn;
- UInt32 idx;
- OSStatus err;
- SInt32* done;
- PVCAddress* pvc;
- ATMVCParams* connParams;
- ATMSimpleQOS* simpleQOS;
- UInt32 flags;
- UInt32 peak_Kilocells;
- union DL_primitives* dp = (union DL_primitives*) mp->b_cont->b_rptr;
-
- // DEBUG_BREAK("atmdlpi: ATMDLPI_IOCTL_subs_connect: ");
-
- if ((minorDev->dlstate != DL_IDLE) && (minorDev->dlstate != DL_DATAXFER)) {
- ERROR_BREAK("atmdlpi: ATMDLPI_IOCTL_subs_connect: DLPI not in DL_DATAXFER or DL_IDLE state\n");
- return -1;
- }
-
- pvc = (PVCAddress*) (mp->b_cont->b_rptr + ((dl_connect_req_t*) dp)->dl_dest_addr_offset);
- simpleQOS = (ATMSimpleQOS*) (mp->b_cont->b_rptr + ((dl_connect_req_t*) dp)->dl_qos_offset);
- if (simpleQOS->dl_qos_type != DL_QOS_SIMPLE_ATM) {
- ERROR_BREAK("atmdlpi: ATMDLPI_IOCTL_subs_connect: dl_qos_type != DL_QOS_SIMPLE_ATM");
- return -1;
- }
- connParams = &(simpleQOS->params);
-
- flags = connParams->traffic.fwdPeakCellRate01 > 0 ? kVCIOut : 0;
- flags |= connParams->traffic.bwdPeakCellRate01 > 0 ? kVCIIn : 0;
- if ( (!validate_pvc(pvc)) ||
- (find_connection(pvc->vpi, pvc->vci, flags) != NULL) ||
- (!validate_aal(connParams->aal)) ||
- (!validate_traffic(&(connParams->traffic) )) ||
- (!validate_qos(connParams->qos)) ) {
- ERROR_SPRINTF((tempstr,"atmdlpi: ATMDLPI_IOCTL_subs_connect: vpi,vci %u,%u can not be validated\n", conn->pvc.vpi, conn->pvc.vci));
- ERROR_BREAK(tempstr);
- return -1;
- }
-
-
- /*
- * Allocate and store a free connection table entry.
- */
- for (idx = 0; idx < MAX_CONNECTIONS; ++idx)
- if (gPortPrivateData->connectTable[idx]==0) break;
- if ( idx >= MAX_CONNECTIONS ) {
- ERROR_BREAK("atmdlpi: ATMDLPI_IOCTL_subs_connect: connection table full\n");
- return ENOMEM;
- }
-
- minorDev->numConnections++;
- minorDev->useUDInd = 1;
-
- gPortPrivateData->connectTable[idx] = conn = (ConnectTableEntry*) OTAllocMem(sizeof(ConnectTableEntry));
- if (idx > gPortPrivateData->maxConnectTableIndex) gPortPrivateData->maxConnectTableIndex = idx;
-
- /*
- * assign values from the subs_connect message into
- * local storage.
- */
- conn->connectTableIndex = idx;
- conn->rdq = minorDev->rdq;
- conn->parentMinorDevice = minorDev;
- conn->nextConnection = (ConnectTableEntry*) 0;
- conn->prevConnection = (ConnectTableEntry*) 0;
- conn->pvc = *pvc;
- conn->aal = connParams->aal;
- conn->qos = connParams->qos;
- conn->traffic = connParams->traffic;
- conn->flags = flags;
-
- /*
- * chain up the connection table entry before the first
- * connection.
- */
- conn->nextConnection = minorDev->firstConnection;
- conn->prevConnection = 0;
- minorDev->firstConnection->prevConnection = conn;
- minorDev->firstConnection = conn;
-
- /* bump up the current peak rates allocated */
- if (!connParams->traffic.bstEffortReq) {
- gPortPrivateData->currentFwdPeakCellRateAllocated += connParams->traffic.fwdPeakCellRate01;
- gPortPrivateData->currentBwdPeakCellRateAllocated += connParams->traffic.bwdPeakCellRate01;
- }
-
- /* Activate an incoming vci, some cards need to activate outgoing vci too */
- if (conn->flags & kVCIIn) {
-
- err = ABCVendorActivateVCI(conn);
- if (err) {
- ERROR_SPRINTF((tempstr,"atmdlpi: ATMDLPI_connect_req: ABCVendorActivateVCI returned error %d\n", err));
- ERROR_BREAK(tempstr);
- (void) ATMDLPI_error_ack(minorDev, mp, DL_CONNECT_REQ, DL_BADADDR, 0);
- return kdlpiDONE;
- }
- }
-
- if (minorDev->dlstate == DL_IDLE)
- minorDev->dlstate = DL_DATAXFER;
-
- return 0;
- }
-
- //-----------------------------------------------------------------------------------------
- // ATMDLPI_SUBS_DISCONNECT Ioctl handling
- //-----------------------------------------------------------------------------------------
-
- static int ATMDLPI_IOCTL_subs_disconnect(MinorDeviceTableEntry* minorDev, mblk_t* mp)
- {
- ConnectTableEntry* conn;
- OSStatus err;
- PVCAddress* pvc;
- ATMVCParams* connParams;
- ATMSimpleQOS* simpleQOS;
- UInt32 flags;
- union DL_primitives* dp = (union DL_primitives*) mp->b_cont->b_rptr;
-
- // DEBUG_BREAK("atmdlpi: ATMDLPI_IOCTL_subs_disconnect:");
-
- if (minorDev->dlstate != DL_DATAXFER) {
- ERROR_BREAK("atmdlpi: ATMDLPI_IOCTL_subs_disconnect: DLPI not in DATAXFER state\n");
- return -1;
- }
-
- /*
- * assign values from the subs_connect message into
- * local storage.
- */
- pvc = (PVCAddress*) (mp->b_cont->b_rptr + ((dl_connect_req_t*) dp)->dl_dest_addr_offset);
- simpleQOS = (ATMSimpleQOS*) (mp->b_cont->b_rptr + ((dl_connect_req_t*) dp)->dl_qos_offset);
- if (simpleQOS->dl_qos_type != DL_QOS_SIMPLE_ATM) {
- ERROR_BREAK("atmdlpi: ATMDLPI_IOCTL_subs_disconnect: dl_qos_type != DL_QOS_SIMPLE_ATM");
- return -1;
- }
- connParams = &(simpleQOS->params);
-
- flags = connParams->traffic.fwdPeakCellRate01 > 0 ? kVCIOut : 0;
- flags |= connParams->traffic.bwdPeakCellRate01 > 0 ? kVCIIn : 0;
-
- conn = find_connection(pvc->vpi, pvc->vci, flags);
-
- if (conn==NULL) return -1;
- else {
- err = disconnect_pvc(minorDev, conn);
- }
-
- return err;
- }
-
- //-----------------------------------------------------------------------------------------
- // DL_UDQOS_REQ handling
- //-----------------------------------------------------------------------------------------
-
- static int ATMDLPI_udqos_req(MinorDeviceTableEntry* minorDev, mblk_t* mp)
- {
- ERROR_BREAK("atmdlpi: ATMDLPI_udqos_req: unimplemented");
-
- return kOTNoError;
- }
-
- //-----------------------------------------------------------------------------------------
- // DL_UDERROR_IND generation
- //-----------------------------------------------------------------------------------------
-
- static void ATMDLPI_uderror_ind(MinorDeviceTableEntry* minorDev, UInt8 *dest, UInt32 destlen,
- UInt32 err, UInt32 uerr)
- {
- dl_uderror_ind_t *errp;
- mblk_t *bp;
- SInt32 bufsize;
-
- // DEBUG_BREAK("atmdlpi: ATMDLPI_uderror_ind:");
-
- bufsize = DL_UDERROR_IND_SIZE + destlen;
-
- if ((bp = allocb(bufsize, BPRI_HI)) == NULL) {
- ERROR_BREAK("atmdlpi: ATMDLPI_uderror_ind: allocb failed");
- return;
- }
-
- bp->b_datap->db_type = M_PROTO;
- errp = (dl_uderror_ind_t *) bp->b_wptr;
- errp->dl_primitive = DL_UDERROR_IND;
- errp->dl_errno = err;
- errp->dl_unix_errno = uerr;
- errp->dl_dest_addr_length = destlen;
- errp->dl_dest_addr_offset = DL_UDERROR_IND_SIZE;
- bp->b_wptr += DL_UDERROR_IND_SIZE;
- bcopy((UInt8 *)dest, (UInt8 *)bp->b_wptr, destlen);
- bp->b_wptr += destlen;
-
- putnext(minorDev->rdq, bp);
-
- return;
- }
-
- //-----------------------------------------------------------------------------------------
- // DL_UNITDATA_REQ handling
- //-----------------------------------------------------------------------------------------
-
- static int ATMDLPI_unitdata_req(MinorDeviceTableEntry* minorDev, mblk_t* mp, UInt8 defaultQFlag)
- {
-
- PVCAddress* transmitPVC;
- OSStatus err;
- ConnectTableEntry* conn;
-
- if (minorDev->dlstate != DL_DATAXFER) {
- ATMDLPI_uderror_ind(minorDev, mp->b_rptr + ((dl_unitdata_req_t *) mp->b_rptr)->dl_dest_addr_offset,
- ((dl_unitdata_req_t *) mp->b_rptr)->dl_dest_addr_length, DL_OUTSTATE, 0);
- freemsg(mp);
- return kdlpiDONE;
- }
-
- if (defaultQFlag) {
-
- conn = minorDev->firstConnection;
-
- err = ABCVendorTransmit(conn, conn->pvc.vpi, conn->pvc.vci, mp);
- if (err==kFlowControl) {
- // DEBUG_SPRINTF((tempstr, "atmdlpi: ATMDLPI_unitdata_req: ABCVendorTransmit flow control experienced %ld\n",err));
- // DEBUG_BREAK(tempstr);
- return kdlpiRETRY;
- }
- if (err) {
- FATAL_SPRINTF((tempstr, "atmdlpi: ATMDLPI_unitdata_req: ABCVendorTransmit error %ld\n",err));
- FATAL_BREAK(tempstr);
- return kdlpiDONE;
- }
-
- }
- else {
-
- mblk_t* proto_mp = mp;
-
- if (((dl_unitdata_req_t *) proto_mp->b_rptr)->dl_dest_addr_length != sizeof(PVCAddress)) {
- ERROR_BREAK("atmdlpi: atm_wput: length of dest, address in Unit Data req incorrect\n");
- ATMDLPI_uderror_ind(minorDev, mp->b_rptr + ((dl_unitdata_req_t *) mp->b_rptr)->dl_dest_addr_offset,
- ((dl_unitdata_req_t *) mp->b_rptr)->dl_dest_addr_length, DL_BADADDR, 0);
- freemsg(mp);
- return kdlpiDONE;
- }
-
- mp = mp->b_cont;
-
- transmitPVC = (PVCAddress*) (proto_mp->b_rptr + ((dl_unitdata_req_t *) proto_mp->b_rptr)->dl_dest_addr_offset);
-
- err = ABCVendorTransmit((ConnectTableEntry*) NULL, transmitPVC->vpi, transmitPVC->vci, mp);
- if (err==kFlowControl) {
- // DEBUG_SPRINTF((tempstr, "atmdlpi: ATMDLPI_unitdata_req: ABCVendorTransmit flow control experienced %ld\n",err));
- // DEBUG_BREAK(tempstr);
- return kdlpiRETRY;
- }
- if (err) {
- FATAL_SPRINTF((tempstr, "atmdlpi: ATMDLPI_unitdata_req: ABCVendorTransmit error %ld\n",err));
- FATAL_BREAK(tempstr);
- return kdlpiDONE;
- }
-
- proto_mp->b_cont = (mblk_t*) NULL;
- freeb(proto_mp);
- }
-
- return kdlpiDONE;
- }
-
- //-----------------------------------------------------------------------------------------
- // DL_UNITDATA_IND generation
- //-----------------------------------------------------------------------------------------
-
- void ATMDLPI_unitdata_ind(ConnectTableEntry* conn, UInt16 vpi, UInt16 vci, mblk_t* mp)
- {
- mblk_t* nmp;
- UInt8* dlSrcPtr;
- dl_unitdata_ind_t *ind;
-
- // DEBUG_SPRINTF((tempstr,"atmdlpi: ATMDLPI_unitdata_ind: vci %u,%u", vpi, vci));
- // DEBUG_BREAK(tempstr);
-
- if ((conn==NULL) && ((conn = find_connection(vpi, vci, kVCIIn))==NULL)) {
- DEBUG_SPRINTF((tempstr,"atmdlpi: ATMDLPI_unitdata_ind: could not find vci %u,%u", vpi, vci));
- DEBUG_BREAK(tempstr);
- freemsg(mp);
- return;
- }
-
- if ( (conn->parentMinorDevice->useUDInd) &&
- ((nmp = allocb(kGoodUDIndSize, BPRI_HI)) != NULL) ) {
-
- nmp->b_cont = mp;
- mp = nmp;
-
- nmp->b_datap->db_type = M_PROTO;
-
- ind = (dl_unitdata_ind_t*) nmp->b_rptr;
- ind->dl_primitive = DL_UNITDATA_IND;
- ind->dl_dest_addr_length = 0;
- ind->dl_dest_addr_offset = 0;
- ind->dl_src_addr_length = sizeof(PVCAddress);
- ind->dl_src_addr_offset = sizeof(dl_unitdata_ind_t);
- ind->dl_group_address = 0; /* Standard address i.e. not multicast or broadcast */
-
- nmp->b_wptr += (sizeof(dl_unitdata_ind_t) + sizeof(PVCAddress));
-
- dlSrcPtr= ((UInt8*)(nmp->b_rptr + ind->dl_src_addr_offset));
- bcopy( (char *) &(conn->pvc), (char *) dlSrcPtr, sizeof(PVCAddress));
- }
-
- if ( (conn->rdq->q_next == (queue_t *) 0) || (!bcanput(conn->rdq->q_next, mp->b_band)) ) {
- // DEBUG_SPRINTF((tempstr,"atmdlpi: ATMDLPI_unitdata_ind: atmdlpi readq is full %d\n", conn->rdq->q_count));
- // DEBUG_BREAK(tempstr);
-
- /*
- * ATM Forum ABR/UBR schemes must be invoked here.
- */
-
- // if (qsize(conn->rdq) > kMaxPendingRecvMessages) {
- freemsg(mp);
- // }
- // else {
- // putq(conn->rdq, mp);
- // }
-
- return;
- }
-
- if (qsize(conn->rdq)) {
- putq(conn->rdq, mp);
- }
- else {
- putnext(conn->rdq, mp);
- }
-
- return;
- }
-
- //-----------------------------------------------------------------------------------------
- // DL_ERROR_ACK generation
- //-----------------------------------------------------------------------------------------
-
- static int ATMDLPI_error_ack(MinorDeviceTableEntry* minorDev, mblk_t *ack_mp, UInt32 prim,
- UInt32 err, UInt32 uerr)
- {
- dl_error_ack_t *errp;
-
- // DEBUG_BREAK("atmdlpi: ATMDLPI_error_ack:");
-
- if (ack_mp == NULL) {
- if ((ack_mp = allocb(DL_ERROR_ACK_SIZE, BPRI_HI)) == NULL) {
- ERROR_BREAK("atmdlpi: ATMDLPI_error_ack: allocb failed");
- return kdlpiRETRY;
- }
- }
- else {
- ack_mp->b_rptr = ack_mp->b_wptr = ack_mp->b_datap->db_base;
- if (ack_mp->b_cont != (mblk_t *) 0) {
- freemsg(ack_mp->b_cont);
- ack_mp->b_cont = (mblk_t *) 0;
- }
- }
-
- ack_mp->b_datap->db_type = M_PCPROTO;
- ack_mp->b_rptr = ack_mp->b_wptr = ack_mp->b_datap->db_base;
- errp = (dl_error_ack_t *)ack_mp->b_rptr;
- errp->dl_primitive = DL_ERROR_ACK;
- errp->dl_error_primitive = prim;
- errp->dl_errno = err;
- errp->dl_unix_errno = uerr;
- ack_mp->b_wptr += DL_ERROR_ACK_SIZE;
-
- putnext(minorDev->rdq, ack_mp);
- return kdlpiDONE;
- }
-
- //-----------------------------------------------------------------------------------------
- // DL_OK_ACK generation
- //-----------------------------------------------------------------------------------------
-
- static int ATMDLPI_ok_ack(MinorDeviceTableEntry* minorDev, mblk_t* ack_mp, UInt32 primitive)
- {
- dl_ok_ack_t *ackp;
-
- // DEBUG_BREAK("atmdlpi: ATMDLPI_ok_ack:");
-
- if (ack_mp == NULL) {
- if ((ack_mp = allocb(DL_OK_ACK_SIZE, BPRI_HI)) == NULL) {
- ERROR_BREAK("atmdlpi: ATMDLPI_ok_ack: allocb failed");
- return kdlpiRETRY;
- }
- }
- else {
- ack_mp->b_rptr = ack_mp->b_wptr = ack_mp->b_datap->db_base;
- if (ack_mp->b_cont != (mblk_t *) 0) {
- freemsg(ack_mp->b_cont);
- ack_mp->b_cont = (mblk_t *) 0;
- }
- }
-
- ack_mp->b_datap->db_type = M_PCPROTO;
- ackp = (dl_ok_ack_t *) ack_mp->b_rptr;
- ackp->dl_primitive = DL_OK_ACK;
- ackp->dl_correct_primitive = primitive;
- ack_mp->b_wptr += DL_OK_ACK_SIZE;
-
- putnext(minorDev->rdq, ack_mp);
- return kdlpiDONE;
- }
-
-
- /***********************************************************
- *
- * ATM DRIVER DLPI : handling out of memory conditions
- *
- ************************************************************/
-
- #define SECOND 1000000 // in microseconds
-
- //-----------------------------------------------------------------------------------------
- // Description:
- // This routine is used to enable the write queue.
- //
- // Input:
- // p - the stream that contains the write queue that needs to be enabled
- //
- // Output:
- // NONE
- //
- //-----------------------------------------------------------------------------------------
- static void enable_write_queue(SInt32 p)
- {
- MinorDeviceTableEntry* minorDev = (MinorDeviceTableEntry*) p;
-
- if (minorDev->rdq != NULL) {
- minorDev->idType = NULL; // mark us as no event waiting
- qenable(WR(minorDev->rdq));
- }
- }
-
- //-----------------------------------------------------------------------------------------
- // Description:
- // This routine is called when someone cannot allocate a message block for an ack
- // message. This routine says call me when you have enough memory for my
- // message block.
- //
- // Input:
- // minorDev - the MinorDeviceTableEntry to disable until memory is available
- // size - number of bytes needed for the message block
- //
- // Output:
- // NONE
- //
- //-----------------------------------------------------------------------------------------
- static void schedule_write_queue(MinorDeviceTableEntry* minorDev, SInt32 size)
- {
- minorDev->timeoutID = bufcall(size, BPRI_HI, enable_write_queue, (SInt32) minorDev);
- if (minorDev->timeoutID == 0) {
- ERROR_BREAK("atmdlpi: schedule_write_queue: bufcall failed");
- // minorDev->timeoutID = timeout(enable_write_queue, (UInt8 *)minorDev, SECOND);
- // minorDev->idType = kdlpiTimerType; // oh well, use timeout
- }
- else
- minorDev->idType = kdlpiBufcallType;
-
- }
-
-
- /***********************************************************
- *
- * ATM DRIVER DLPI : Searching the connectTable
- *
- ************************************************************/
-
- /* The last ConnectTableEntry index successfully returned */
- static last_i = 0;
-
- //-----------------------------------------------------------------------------------------
- // Find the ConnectTableEntry, given the vpi, vci and flags
- // This could be more efficient :-).
- //-----------------------------------------------------------------------------------------
-
- ConnectTableEntry* find_connection(UInt16 vpi, UInt16 vci, UInt32 flags)
- {
- register int i;
- register ConnectTableEntry* conn = gPortPrivateData->connectTable[last_i];
-
- if ( (conn) &&
- (vci == conn->pvc.vci) &&
- (vpi == conn->pvc.vpi) &&
- ((flags & conn->flags) == flags) )
- return conn;
-
- for (i=0; i<=gPortPrivateData->maxConnectTableIndex; i++) {
- conn = gPortPrivateData->connectTable[i];
- if ( (conn) &&
- (vci == conn->pvc.vci) &&
- (vpi == conn->pvc.vpi) &&
- ((flags & conn->flags) == flags) ) {
- last_i = i;
- return conn;
- }
- }
-
- // DEBUG_BREAK("atmdlpi: find_connection: could not find it");
-
- return((ConnectTableEntry *) NULL);
- }
-